/* * $Id: IWNavigationHandlerImpl.java,v 1.5 2006/05/11 17:06:38 eiki Exp $ * Created on Nov 8, 2005 * * Copyright (C) 2005 Idega Software hf. All Rights Reserved. * * This software is the proprietary information of Idega hf. Use is subject to * license terms. */ package com.idega.faces.navigation; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.faces.FacesException; import javax.faces.application.NavigationHandler; import javax.faces.application.ViewHandler; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.myfaces.application.NavigationHandlerImpl; import org.apache.myfaces.config.RuntimeConfig; import org.apache.myfaces.config.element.NavigationCase; import org.apache.myfaces.config.element.NavigationRule; import org.apache.myfaces.portlet.PortletUtil; import org.apache.myfaces.shared_impl.util.HashMapUtils; import com.idega.core.view.ViewManager; import com.idega.core.view.ViewNode; public class IWNavigationHandlerImpl extends NavigationHandler { private static final Log log = LogFactory.getLog(NavigationHandlerImpl.class); private static final String ASTERISK = "*"; private Map _navigationCases = null; private List _wildcardKeys = new ArrayList(); public IWNavigationHandlerImpl() { if (log.isTraceEnabled()) { log.trace("New NavigationHandler instance created"); } } public void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { if (outcome == null) { // stay on current ViewRoot return; } // switch to page uri if the view id represents a builder page stored as jsp String viewId = facesContext.getViewRoot().getViewId(); ViewManager viewManager = ViewManager.getInstance(facesContext); ViewNode viewNode = viewManager.getViewNodeForContext(facesContext); if (viewNode != null) { // if viewNode is not null we have a request for an URI in the ViewNode // structure String pageUri = viewManager.getRequestUriWithoutContext(facesContext); if (pageUri != null) { // something like "/pages/test/hello/" or "/workspace/builder/" viewId = pageUri; } } Map casesMap = getNavigationCases(facesContext); NavigationCase navigationCase = null; List casesList = (List) casesMap.get(viewId); if (casesList != null) { // Exact match? navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome); } if (navigationCase == null) { // Wildcard match? List keys = getSortedWildcardKeys(); for (int i = 0, size = keys.size(); i < size; i++) { String fromViewId = (String) keys.get(i); if (fromViewId.length() > 2) { String prefix = fromViewId.substring(0, fromViewId.length() - 1); if (viewId != null && viewId.startsWith(prefix)) { casesList = (List) casesMap.get(fromViewId); if (casesList != null) { navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome); if (navigationCase != null) { break; } } } } else { casesList = (List) casesMap.get(fromViewId); if (casesList != null) { navigationCase = calcMatchingNavigationCase(casesList, fromAction, outcome); if (navigationCase != null) { break; } } } } } if (navigationCase != null) { if (log.isTraceEnabled()) { log.trace("handleNavigation fromAction=" + fromAction + " outcome=" + outcome + " toViewId =" + navigationCase.getToViewId() + " redirect=" + navigationCase.isRedirect()); } if (navigationCase.isRedirect() && (!PortletUtil.isPortletRequest(facesContext))) { // Spec // section // 7.4.2 // says // "redirects // not // possible" // in // this // case // for // portlets ExternalContext externalContext = facesContext.getExternalContext(); ViewHandler viewHandler = facesContext.getApplication().getViewHandler(); String redirectPath = viewHandler.getActionURL(facesContext, navigationCase.getToViewId()); try { externalContext.redirect(externalContext.encodeActionURL(redirectPath)); } catch (IOException e) { throw new FacesException(e.getMessage(), e); } facesContext.responseComplete(); } else { ViewHandler viewHandler = facesContext.getApplication().getViewHandler(); // create new view String newViewId = navigationCase.getToViewId(); UIViewRoot viewRoot = viewHandler.createView(facesContext, newViewId); viewRoot.setViewId(newViewId); facesContext.setViewRoot(viewRoot); facesContext.renderResponse(); } } else { // no navigationcase found, stay on current ViewRoot if (log.isTraceEnabled()) { log.trace("handleNavigation fromAction=" + fromAction + " outcome=" + outcome + " no matching navigation-case found, staying on current ViewRoot"); } } } private NavigationCase calcMatchingNavigationCase(List casesList, String actionRef, String outcome) { for (int i = 0, size = casesList.size(); i < size; i++) { NavigationCase caze = (NavigationCase) casesList.get(i); String cazeOutcome = caze.getFromOutcome(); String cazeActionRef = caze.getFromAction(); if ((cazeOutcome == null || cazeOutcome.equals(outcome)) && (cazeActionRef == null || cazeActionRef.equals(actionRef))) { return caze; } } return null; } private List getSortedWildcardKeys() { return this._wildcardKeys; } private Map getNavigationCases(FacesContext facesContext) { ExternalContext externalContext = facesContext.getExternalContext(); RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext); if (this._navigationCases == null || runtimeConfig.isNavigationRulesChanged()) { synchronized (this) { if (this._navigationCases == null || runtimeConfig.isNavigationRulesChanged()) { Collection rules = runtimeConfig.getNavigationRules(); int rulesSize = rules.size(); Map cases = new HashMap(HashMapUtils.calcCapacity(rulesSize)); List wildcardKeys = new ArrayList(); for (Iterator iterator = rules.iterator(); iterator.hasNext();) { NavigationRule rule = (NavigationRule) iterator.next(); String fromViewId = rule.getFromViewId(); // specification 7.4.2 footnote 4 - missing fromViewId is allowed: if (fromViewId == null) { fromViewId = ASTERISK; } else { fromViewId = fromViewId.trim(); } List list = (List) cases.get(fromViewId); if (list == null) { list = new ArrayList(rule.getNavigationCases()); cases.put(fromViewId, list); if (fromViewId.endsWith(ASTERISK)) { wildcardKeys.add(fromViewId); } } else { list.addAll(rule.getNavigationCases()); } } Collections.sort(wildcardKeys, new KeyComparator()); synchronized (cases) { // We do not really need this sychronization at all, but this // gives us the peace of mind that some good optimizing compiler // will not rearrange the execution of the assignment to an // earlier time, before all init code completes this._navigationCases = cases; this._wildcardKeys = wildcardKeys; runtimeConfig.setNavigationRulesChanged(false); } } } } return this._navigationCases; } protected static final class KeyComparator implements Comparator { public int compare(Object o1, Object o2) { return -(((String) o1).compareTo((String) o2)); } } }